// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <pollux/testing/gtest_utils.h>
#include <pollux/dwio/common/range.h>

using namespace ::testing;

namespace kumo::pollux::common {

TEST(RangeTests, Add) {
  Ranges ranges;
  POLLUX_ASSERT_THROW(ranges.add(2, 1), "");
  ranges.add(2, 2);
  ranges.add(1, 3);
  ASSERT_THAT(ranges.ranges_, ElementsAre(std::tuple<size_t, size_t>{1, 3}));
  ASSERT_EQ(ranges.size(), 2);
  ranges.add(3, 5);
  ASSERT_THAT(ranges.ranges_, ElementsAre(std::tuple<size_t, size_t>{1, 5}));
  ASSERT_EQ(ranges.size(), 4);
  ranges.add(6, 9);
  ASSERT_THAT(
      ranges.ranges_,
      ElementsAre(
          std::tuple<size_t, size_t>{1, 5}, std::tuple<size_t, size_t>{6, 9}));
  ASSERT_EQ(ranges.size(), 7);
  ranges.add(8, 10);
  ASSERT_THAT(
      ranges.ranges_,
      ElementsAre(
          std::tuple<size_t, size_t>{1, 5},
          std::tuple<size_t, size_t>{6, 9},
          std::tuple<size_t, size_t>{8, 10}));
  ranges.clear();
  ASSERT_EQ(ranges.size(), 0);
}

TEST(RangeTests, ForEach) {
  Ranges ranges;
  ranges.add(1, 3);
  ranges.add(6, 9);
  auto total = 0;
  ASSERT_EQ(ranges.size(), 5);
  for (auto& i : ranges) {
    total += i;
  }
  ASSERT_EQ(total, 24);
}

TEST(RangeTests, Filter) {
  auto r = Ranges::of(1, 10);
  auto r2 = r.filter([](auto /* unused */) { return true; });
  ASSERT_EQ(r2.size(), 9);
  ASSERT_THAT(r2.ranges_, ElementsAre(std::tuple<size_t, size_t>{1, 10}));

  auto r3 = r.filter([](auto i) { return i % 3 != 0; });
  ASSERT_EQ(r3.size(), 6);
  ASSERT_THAT(
      r3.ranges_,
      ElementsAre(
          std::tuple<size_t, size_t>{1, 3},
          std::tuple<size_t, size_t>{4, 6},
          std::tuple<size_t, size_t>{7, 9}));

  Ranges r4;
  r4.add(1, 10);
  r4.add(20, 30);
  auto r5 = r4.filter([](auto i) { return i != 3 && i != 8 && i != 25; });
  ASSERT_EQ(r5.size(), 16);
  ASSERT_THAT(
      r5.ranges_,
      ElementsAre(
          std::tuple<size_t, size_t>{1, 3},
          std::tuple<size_t, size_t>{4, 8},
          std::tuple<size_t, size_t>{9, 10},
          std::tuple<size_t, size_t>{20, 25},
          std::tuple<size_t, size_t>{26, 30}));
}

} // namespace kumo::pollux::common
